package com.zff.rental.service.oss;


import com.zff.rental.common.BusinessException;
import com.zff.rental.config.MinioConfig;
import io.minio.*;
import io.minio.errors.*;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.UUID;

/**
 * Oss服务
 *
 * @author HCY
 */
@Service
@Slf4j
public class OssService {
    @Resource
    private MinioConfig minioConfig;

    /**
     * 根据业务类型生成文件的objectKey
     *
     * @param businessType 业务类型
     * @param fileName     文件名称
     * @return 文件对象key
     */
    private String generateObjectKey(String businessType, String fileName) {
        if (fileName == null || fileName.trim().isEmpty()) {
            fileName = UUID.randomUUID().toString().replaceAll("-", "");
        }

        if (businessType == null) {
            return fileName;
        }
        if (fileName.startsWith("/") || fileName.startsWith("\\")) {
            return businessType + fileName;
        } else {
            return businessType + "/" + fileName;
        }
    }

    public String upload(MultipartFile file, String fileName, String businessType) {
        String objectKey = generateObjectKey(businessType, fileName);

        try {
            if (isExist(objectKey)) {
                throw new BusinessException("文件已存在");
            }
        } catch (Exception e) {
            throw new BusinessException("上传失败: " + e);
        }

        try (InputStream inputStream = file.getInputStream()) {
            PutObjectArgs request = PutObjectArgs.builder()
                    .bucket(minioConfig.getDefaultBucketName())
                    .object(objectKey)
                    .stream(inputStream, file.getSize(), -1)
                    .build();
            minioConfig.getMinioClient().putObject(request);
        } catch (Exception e) {
            throw new BusinessException("上传失败: " + e);
        }

        return objectKey;
    }

    public void download(String objectKey, HttpServletResponse response) {
        GetObjectArgs request = GetObjectArgs.builder()
                .bucket(minioConfig.getDefaultBucketName())
                .object(objectKey)
                .build();
        try (OutputStream outputStream = response.getOutputStream()) {
            GetObjectResponse object = minioConfig.getMinioClient().getObject(request);
            object.transferTo(outputStream);
        } catch (Exception e) {
            throw new BusinessException("下载文件失败: " + e);
        }
    }

    public boolean isExist(String objectKey) {
        StatObjectArgs statObjectArgs = StatObjectArgs.builder().bucket(minioConfig.getDefaultBucketName()).object(objectKey).build();
        try {
            minioConfig.getMinioClient().statObject(statObjectArgs);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    public void move(String sourceKey, String destinationKey) throws ServerException, InsufficientDataException,
            ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException,
            XmlParserException, InternalException {
        // 复制文件
        CopyObjectArgs copyObjectRequest = CopyObjectArgs.builder()
                .bucket(minioConfig.getDefaultBucketName())
                .object(destinationKey)
                .source(CopySource.builder().bucket(minioConfig.getDefaultBucketName()).object(sourceKey).build())
                .build();
        minioConfig.getMinioClient().copyObject(copyObjectRequest);

        // 删除原始文件
        RemoveObjectArgs deleteObjectRequest = RemoveObjectArgs.builder()
                .bucket(minioConfig.getDefaultBucketName())
                .object(sourceKey)
                .build();
        minioConfig.getMinioClient().removeObject(deleteObjectRequest);
    }
}
